// Copyright (c) 2020-present, INSPUR Co, Ltd. All rights reserved.
// This source code is licensed under Apache 2.0 License.
//
// Created by florian on 18.11.15.

#pragma once
#include "abstract_loadkey.h"
#include "art_n.h"

const bool ART_PRINT_LOG = false;

namespace art_rowex {

class Tree {

private:
  N *const root;

  TID checkKey(const TID tid, const Key &k) const;

  ILoadKey *loadKey_;

public:
  enum class CheckPrefixResult : uint8_t { Match, NoMatch, OptimisticMatch };

  enum class CheckPrefixPessimisticResult : uint8_t {
    Match,
    NoMatch,
    SkippedLevel
  };

  enum class PCCompareResults : uint8_t {
    Smaller,
    Equal,
    Bigger,
    SkippedLevel
  };
  enum class PCEqualsResults : uint8_t {
    BothMatch,
    Contained,
    NoMatch,
    SkippedLevel
  };
  static CheckPrefixResult checkPrefix(N *n, const Key &k, uint32_t &level);
  static CheckPrefixResult checkPrefixOnly(N *n, const Key &k, uint32_t &level);
  static int comparePrefixOnly(N *n, const Key &k, uint32_t level);

  static CheckPrefixPessimisticResult
  checkPrefixPessimistic(N *n, const Key &k, uint32_t &level,
                         uint8_t &nonMatchingKey, Prefix &nonMatchingPrefix,
                         ILoadKey *loadKey);
  static CheckPrefixPessimisticResult
  checkPrefixMatch(N *n, const Key &k, uint32_t &level, uint8_t &nonMatchingKey,
                   Prefix &nonMatchingPrefix, ILoadKey *loadKey);

  static PCCompareResults checkPrefixCompare(const N *n, const Key &k,
                                             uint32_t &level,
                                             ILoadKey *loadKey);

  static PCEqualsResults checkPrefixEquals(const N *n, uint32_t &level,
                                           const Key &start, const Key &end,
                                           ILoadKey *loadKey);

public:
  Tree(ILoadKey *loadKey);

  Tree(const Tree &) = delete;
  Tree(Tree &&t) = delete;
  Tree &operator=(const Tree &) = delete;
  Tree &operator=(Tree &&) = delete;

  ~Tree();

  void insertOrGetLG(const Key &k, TID tid, TID &curTID, TID &nextTID);
  TID getLG(const Key &key) { return this->seek(key, false, true); }
  TID get(const Key &key) { return this->seek(key, true, false); }
  TID getEG(const Key &key) { return this->seek(key, true, true); }

  void remove(const Key &k, TID tid) const;
  // compare key in TID and k, just length prefix will be compared.
  int compareKeyPrefix(const TID tid, const Key &k, int length) const;

private:
  // current node min in TID.
  TID getMinTID(N *node, uint8_t start) const;
  // current node max key in TID.
  TID getMaxTID(N *node, uint8_t end) const;
  TID seek(const Key &k, bool equal, bool greater) const;
  TID seekChildren(N *node, const Key &k, uint32_t level, bool equal,
                   bool greater) const;

  // recursive function
  TID getChildEG(N *node, const Key &k, uint32_t level, bool justGreater,
                 bool prevMatch = true) const;
};
} // namespace art_rowex
